import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from pandas.plotting import register_matplotlib_converters
from pyod.models.cof import COF 
from sklearn.cluster import DBSCAN
from sklearn.ensemble import IsolationForest 
from sklearn.neighbors import NearestNeighbors,LocalOutlierFactor

class DataAnalyzer:
    def __init__(self, file_path, sheet_name):
        self.data = pd.read_excel(file_path, sheet_name=sheet_name)
        self.process_data()
        
    def process_data(self):
        self.data['date'] = pd.to_datetime(self.data['date'].astype(str), format='%Y%m%d')
        self.data['date'] = self.data['date'] + pd.to_timedelta(self.data['hour'].astype(int), unit='H')
    
    def sigma_3(self):
        y = self.data['转化值']
        mu, std = np.mean(y), np.std(y)
        low, upp = mu - 3*std, mu + 3*std
        red_points = []
        non_red_points = []

        for i, j in enumerate(y):
            if j <= low or j >= upp:
                red_points.append(i)
                print(f"{j}", f"{self.data['date'][i]}")
            else:
                non_red_points.append(i)
        
        return red_points, non_red_points
    
    def boxplot(self):
        y = self.data['转化值']
        q1, q3 = y.quantile(.25) , y.quantile(.75)
        iqr = q3 - q1
        red_points = []
        non_red_points = []
        low , upp = q1 - 1.5*iqr , q3 + 1.5*iqr
        for i, j in enumerate(y):
            if j <= low or j >= upp:
                red_points.append(i)
                print(f"{j}", f"{self.data['date'][i]}")
            else:
                non_red_points.append(i)

    def cof(self):
        y = self.data['转化值']
        cof_models = COF(contamination=0.06,n_neighbors=20)
        cof_label = cof_models.fit_predict(y.values.reshape(-1,1))
        red_points = np.where(cof_label == 1)[0]
        non_red_points = np.setdiff1d(np.arange(len(y)), red_points)

    def dbscan(self):
        y = self.data['转化值']
        clustering = DBSCAN(eps = 3,min_samples = 2).fit(y.values.reshape(-1,1))
        red_points = np.where(clustering.labels_ == -1)[0]
        non_red_points = np.setdiff1d(np.arange(len(y)), red_points)

    def isolationforest(self):
        y = self.data['转化值']
        isolation_forest_model = IsolationForest(contamination=0.1)
        isolation_forest_model.fit(y.values.reshape(-1,1))
        labels = isolation_forest_model.predict(y.values.reshape(-1,1))
        red_points = np.where(labels == -1)[0]
        non_red_points = np.setdiff1d(np.arange(len(y)), red_points)

    def knn(self):
        y = self.data['转化值']
        k = 3
        knn_model = NearestNeighbors(n_neighbors=k)
        knn_model.fit(y.values.reshape(-1, 1)) 
        distances, indices = knn_model.kneighbors(y.values.reshape(-1, 1)) 
        threshold_distance = np.percentile(distances[:, -1], 85)
        red_points = np.where(distances[:, -1] > threshold_distance)[0]
        non_red_points = np.setdiff1d(np.arange(len(y)), red_points)

    def lof(self):
        y = self.data['转化值']
        lof_model = LocalOutlierFactor(n_neighbors=3)
        lof_scores = lof_model.fit_predict(y.values.reshape(-1,1))
        red_points = np.where(lof_scores == -1)[0]
        non_red_points = np.setdiff1d(np.arange(len(y)), red_points)
            
    def plot_data(self, red_points):
        x = self.data['date']
        y = self.data['转化值']
        mu, std = np.mean(y), np.std(y)

        plt.figure(figsize=(10, 6))  
        plt.scatter(x[red_points], y[red_points], color='red', label='High Activation')
        plt.plot(x, y, color='blue', label='Normal Activation')
        plt.fill_between(x, mu-3*std, mu+3*std, color='gray', alpha=0.2)
        plt.gca().xaxis.set_major_formatter(plt.matplotlib.dates.DateFormatter('%Y-%m-%d'))
        plt.legend()
        plt.title('Active player')
        plt.xlabel('Date')
        plt.ylabel('Activation')
        plt.gcf().autofmt_xdate()
        plt.show()

file_path = 'data2.xlsx'
sheet_name = '20013'
data_analyzer = DataAnalyzer(file_path, sheet_name)
red_points, _ = data_analyzer.sigma_3()
data_analyzer.plot_data(red_points)